Skip to main content

Discrete Staking Rewards

Discrete Staking Rewards

Similar to staking rewards contract. Difference is that reward amount may vary at each second.

Discrete Staking Rewards

离散质押奖励 类似于质押奖励合约。不同之处在于,奖励金额每秒可能会有所不同。

离散质押奖励

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract DiscreteStakingRewards {
IERC20 public immutable stakingToken;
IERC20 public immutable rewardToken;

mapping(address => uint) public balanceOf;
uint public totalSupply;

uint private constant MULTIPLIER = 1e18;
uint private rewardIndex;
mapping(address => uint) private rewardIndexOf;
mapping(address => uint) private earned;

constructor(address _stakingToken, address _rewardToken) {
stakingToken = IERC20(_stakingToken);
rewardToken = IERC20(_rewardToken);
}

function updateRewardIndex(uint reward) external {
rewardToken.transferFrom(msg.sender, address(this), reward);
rewardIndex += (reward * MULTIPLIER) / totalSupply;
}

function _calculateRewards(address account) private view returns (uint) {
uint shares = balanceOf[account];
return (shares * (rewardIndex - rewardIndexOf[account])) / MULTIPLIER;
}

function calculateRewardsEarned(address account) external view returns (uint) {
return earned[account] + _calculateRewards(account);
}

function _updateRewards(address account) private {
earned[account] += _calculateRewards(account);
rewardIndexOf[account] = rewardIndex;
}

function stake(uint amount) external {
_updateRewards(msg.sender);

balanceOf[msg.sender] += amount;
totalSupply += amount;

stakingToken.transferFrom(msg.sender, address(this), amount);
}

function unstake(uint amount) external {
_updateRewards(msg.sender);

balanceOf[msg.sender] -= amount;
totalSupply -= amount;

stakingToken.transfer(msg.sender, amount);
}

function claim() external returns (uint) {
_updateRewards(msg.sender);

uint reward = earned[msg.sender];
if (reward > 0) {
earned[msg.sender] = 0;
rewardToken.transfer(msg.sender, reward);
}

return reward;
}
}

interface IERC20 {
function totalSupply() external view returns (uint);

function balanceOf(address account) external view returns (uint);

function transfer(address recipient, uint amount) external returns (bool);

function allowance(address owner, address spender) external view returns (uint);

function approve(address spender, uint amount) external returns (bool);

function transferFrom(
address sender,
address recipient,
uint amount
) external returns (bool);

event Transfer(address indexed from, address indexed to, uint value);
event Approval(address indexed owner, address indexed spender, uint value);
}